#include <trap.h>
#include <riscv.h>
#include <fmt.h>

void trap_init(void) {
    extern void __alltraps(void);
    write_csr(sscratch, 0);
    write_csr(stvec, (uintptr_t)&__alltraps);
}

void print_trapframe(trapframe_t *tf) {
    printf("trapframe at %p\n", tf);
    print_context(&tf->context);
    printf("  status   0x%08x\n", tf->sstatus);
    printf("  epc      0x%08x\n", tf->sepc);
    printf("  stval    0x%08x\n", tf->stval);
    printf("  cause    0x%08x\n", tf->scause);
}

void print_context(context_t *context) {
    printf("  ra       0x%08x\n", context->ra);
    printf("  sp       0x%08x\n", context->sp);
    printf("  gp       0x%08x\n", context->gp);
    printf("  tp       0x%08x\n", context->tp);
    printf("  t0       0x%08x\n", context->t0);
    printf("  t1       0x%08x\n", context->t1);
    printf("  t2       0x%08x\n", context->t2);
    printf("  s0       0x%08x\n", context->s0);
    printf("  s1       0x%08x\n", context->s1);
    printf("  a0       0x%08x\n", context->a0);
    printf("  a1       0x%08x\n", context->a1);
    printf("  a2       0x%08x\n", context->a2);
    printf("  a3       0x%08x\n", context->a3);
    printf("  a4       0x%08x\n", context->a4);
    printf("  a5       0x%08x\n", context->a5);
    printf("  a6       0x%08x\n", context->a6);
    printf("  a7       0x%08x\n", context->a7);
    printf("  s2       0x%08x\n", context->s2);
    printf("  s3       0x%08x\n", context->s3);
    printf("  s4       0x%08x\n", context->s4);
    printf("  s5       0x%08x\n", context->s5);
    printf("  s6       0x%08x\n", context->s6);
    printf("  s7       0x%08x\n", context->s7);
    printf("  s8       0x%08x\n", context->s8);
    printf("  s9       0x%08x\n", context->s9);
    printf("  s10      0x%08x\n", context->s10);
    printf("  s11      0x%08x\n", context->s11);
    printf("  t3       0x%08x\n", context->t3);
    printf("  t4       0x%08x\n", context->t4);
    printf("  t5       0x%08x\n", context->t5);
    printf("  t6       0x%08x\n", context->t6);
}

void interrupt_handler(trapframe_t *tf) {
    uintptr_t cause = (tf->scause << 1) >> 1;
    printf("interrupt at 0x%08x, cause: %ld\n", tf->sepc, tf->scause);
    print_trapframe(tf);
}

void exception_handler(trapframe_t *tf) {
    printf("exception at 0x%08x, cause: %ld\n", tf->sepc, tf->scause);
    print_trapframe(tf);
}

static inline void trap_handler(trapframe_t *tf) {
    if ((uintptr_t)tf->scause < 0) {
        interrupt_handler(tf);
    } else {
        exception_handler(tf);
    }
}

void trap(trapframe_t *tf) { trap_handler(tf); }